package ic.symbols;

import common.exceptions.SemanticError;
import ic.ast.Visitor;
import ic.ast.decl.DeclField;
import ic.ast.decl.DeclMethod;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * User: Matan
 * Date: 12/10/13
 * Time: 11:20 AM
 */
public class ClassSymbolTable extends SymbolTable {

    private Map<String, FieldSymbol> fieldSymbolMap = new LinkedHashMap<String, FieldSymbol>();
    private Map<String, MethodSymbol> methodSymbolMap = new LinkedHashMap<String, MethodSymbol>();

    public List<FieldSymbol> getFieldSymbols() {
        return new ArrayList<FieldSymbol>(fieldSymbolMap.values());
    }

    public ClassSymbolTable(SymbolTable parent, String name) {
        super(parent, name);
    }

    @Override
    public Symbol lookup(String name) {
        if (fieldSymbolMap.containsKey(name)) {
            return fieldSymbolMap.get(name);
        } else if (methodSymbolMap.containsKey(name)) {
            return methodSymbolMap.get(name);
        } else return parent.lookup(name);
    }

    @Override
    public SymbolTable lookupTable(String name) {
        if (fieldSymbolMap.containsKey(name) || methodSymbolMap.containsKey(name)) {
            return this;
        } else return parent.lookupTable(name);
    }

    @Override
    public Symbol staticLookup(String name) {
        if (fieldSymbolMap.containsKey(name)) {
            return fieldSymbolMap.get(name);
        } else if (methodSymbolMap.containsKey(name)) {
            return methodSymbolMap.get(name);
        } else return null;
    }

    @Override
    public Object accept(Visitor visitor) throws Exception {
        return visitor.visit(this);
    }

    @Override
    public ClassSymbolTable getEnclosingClassTable() {
        return this;
    }

    @Override
    public String getCurrentMethodName() {
        return "";
    }

    public void insert(DeclField newField) throws Exception {
        if (fieldSymbolMap.containsKey(newField.getName())) {
            throw new SemanticError("Field " + newField.getName() + " is shadowing a field with the same name");
        }
        if (methodSymbolMap.containsKey(newField.getName())) {
            throw new SemanticError("Field " + newField.getName() + " is shadowing a method with the same name");
        }
        fieldSymbolMap.put(newField.getName(), new FieldSymbol(newField));
    }

    public void insert(DeclMethod newMethod) throws Exception {
        if (fieldSymbolMap.containsKey(newMethod.getName())) {
            throw new SemanticError("Method " + newMethod.getName() + " is shadowing a field with the same name");
        }
        if (methodSymbolMap.containsKey(newMethod.getName())) {
            throw new SemanticError("Method " + newMethod.getName() + " is shadowing a method with the same name");
        }
        methodSymbolMap.put(newMethod.getName(), new MethodSymbol(newMethod));
    }

    public List<MethodSymbol> getMethodSymbols() {
        return new ArrayList<MethodSymbol>(methodSymbolMap.values());
    }
}

